package cn.edu.tju.fctl.service.impl;

import cn.edu.tju.fctl.dao.*;
import cn.edu.tju.fctl.entities.*;
import cn.edu.tju.fctl.service.IVacationService;
import cn.edu.tju.fctl.util.*;
import cn.edu.tju.fctl.util.VacationStatus;
import cn.edu.tju.fctl.util.VacationStatusUtil;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created by liutong on 15/12/18.
 */
@Service("vacationService")
public class VacationService implements IVacationService {
    final int NUM_OF_DAYS = 3, RATIO = 1000000;
    @Autowired
    LeaveInfoMapper leaveInfoMapper;
    @Autowired
    LeaveLogMapper leaveLogMapper;
    @Autowired
    LeaveDelayMapper leaveDelayMapper;
    @Autowired
    LeaveTimeMapper leaveTimeMapper;
    @Autowired
    UserMapper userMapper;
    @Autowired
    MarkMapper markMapper;

    public LeaveInfo findById(int id){
        return leaveInfoMapper.selectByPrimaryKey(id);
    };

    public int updateLeave(LeaveInfo leaveInfo) {
        return leaveInfoMapper.updateByPrimaryKey(leaveInfo);
    }

    public int updateLeaveDelay(LeaveDelay leaveDelay) {
        return leaveDelayMapper.updateByPrimaryKey(leaveDelay);
    }

    @Transactional
    public int createLeave(LeaveInfo leaveInfo) {
        leaveInfoMapper.insert(leaveInfo);
        for (LeaveTime leaveTime : leaveInfo.getLeaveTimes()) {
            leaveTime.setLeaveId(leaveInfo.getLeaveId());
            leaveTimeMapper.insert(leaveTime);
        }
        return leaveInfo.getLeaveId();
    }

    public List<LeaveInfo> findAllVacationByUserID(int userID) {
        return leaveInfoMapper.selectAllByUserID(userID);
    }

    public List<LeaveLog> findVacationLogByID(int id) {
        return leaveLogMapper.findByLeaveID(id);
    }

    @Transactional
    public int addVacationToDelay(LeaveDelay leaveDelay) {
        LeaveInfo leaveInfo = leaveInfoMapper.selectByPrimaryKey(leaveDelay.getLeaveId());
        leaveInfo.setStatus(VacationStatus.WAITING_FOR_DELAY_APPLY.toString());
        leaveInfoMapper.updateByPrimaryKey(leaveInfo);
        leaveDelayMapper.insert(leaveDelay);
        return leaveDelay.getLeaveDelayId();
//        if (VacationStatusUtil.canStatusChange(leaveInfo, VacationStatus.WAITING_FOR_DELAY_APPLY)) {
//            leaveInfo.setStatus(VacationStatus.WAITING_FOR_DELAY_APPLY.toString());
//            return leaveDelayMapper.insert(leaveDelay);
//        } else {
//            return 0;
//        }

    }

    public LeaveDelay findDelayVacation(int delay_id) {
        return leaveDelayMapper.selectByPrimaryKey(delay_id);
    }

    public List<LeaveInfo> findAllVacationByApproverID(int userId, int page, int num) {
        List<LeaveInfo> res = new ArrayList();

        User user = userMapper.selectByPrimaryKey(userId);
        //check authority
        if(user.getRole().contains(RoleUtil.DEPUTY_MANAGER)){
            res.addAll(leaveInfoMapper.selectForDeputyManager(VacationStatus.WAITING_FOR_FIRST_APPLY.toString(), ""));
            res.addAll(leaveInfoMapper.selectForDeputyManager(VacationStatus.WAITING_FOR_DELAY_APPLY.toString(), VacationStatus.WAITING_FOR_FIRST_APPLY.toString()));
        }
        if(user.getRole().contains(RoleUtil.GENERAL_MANAGER)){
            res.addAll(leaveInfoMapper.selectForGeneralManager(VacationStatus.WAITING_FOR_FIRST_APPLY.toString(), ""));
            res.addAll(leaveInfoMapper.selectForGeneralManager(VacationStatus.WAITING_FOR_DELAY_APPLY.toString(), VacationStatus.WAITING_FOR_FIRST_APPLY.toString()));
        }
        if(user.getRole().contains(RoleUtil.STATISTIC_USER)){
            res.addAll(leaveInfoMapper.selectForStatisticUser(VacationStatus.FIRST_PASSED.toString(), ""));
            res.addAll(leaveInfoMapper.selectForStatisticUser(VacationStatus.WAITING_FOR_DELAY_APPLY.toString(), VacationStatus.FIRST_PASSED.toString()));
        }
        return res;
    }

    public List<VacationType> findFirstVacationType(){
        return VacationTypeUtil.getInstance().getVacationTypes();
    }

    public List<VacationType> findSecondVacationType(int type1Id){
        return VacationTypeUtil.getInstance().getVacationById(type1Id).getSubTypes();
    }

    public List<LeaveInfo> findVacationByUserIDAndDate(int userId, Date fromDate, Date toDate) {
        return leaveInfoMapper.getVacationByUserIDAndDate(userId, fromDate, toDate);
//        return null;
    }

    public Evaluation getEvaluation(int userId, int fromYear, int fromMonth, int toYear, int toMonth){
        Date fromDate, toDate;
        List<Mark> listMark;
        //format date
        if(fromMonth == -1){
            fromMonth = 0;
            toMonth = 11;
        }
        fromDate = new Date(fromYear - 1900,fromMonth,1);
        toDate = getToDate(toYear,toMonth);

        //get data
        List<LeaveInfo> listAllLeave = findVacationByUserIDAndDate(userId,fromDate,toDate);
        listMark = markMapper.getMarkByUserIDAndDate(userId,fromDate,toDate);
        return EvaluationUtil.getInstance().getEvaluation(userId, listAllLeave, listMark,fromDate,toDate);
    }

    public List<Evaluation> getDepartmentEvaluation(int departId, int fromYear, int fromMonth, int toYear, int toMonth) {
        List<User> listUser = userMapper.findByDepart(departId + "");
        List<Evaluation> res = new ArrayList<Evaluation>();
        for(User tempUser:listUser){
            res.add(getEvaluation(tempUser.getUserId(),fromYear,fromMonth,toYear,toMonth));
        }
        return res;
    }

    //to ensure the last day be included completely, end date is setted as the next day,
    // and the time will be 00:00 when run in database.
    private Date getToDate(int toYear, int toMonth) {
        if (toMonth == 12) {
            toYear++;
            toMonth = 1;
        } else {
            toMonth++;
        }
        return new Date(toYear - 1900, toMonth, 1);
    }


    public List<VacationView> getVacationView() {
        return leaveInfoMapper.selectVacationView();
    }


}
